#pragma once

#include <iostream>
#include <string>
#include <ctime>
#include <memory>
#include <jsoncpp/json/json.h>

namespace Protocol_ns
{
	const std::string SEP = "\r\n";

	// 把报头和有效载荷封装成协议,解决粘报问题
	std::string Encode(const std::string &json_str)
	{
		int json_str_len = json_str.size();
		std::string proto_str = std::to_string(json_str_len);
		proto_str += SEP;
		proto_str += json_str;
		proto_str += SEP;
		return proto_str;
	}

	// 获取有效载荷和处理错误数据
	std::string Decode(std::string &inbuffer)
	{
		auto pos = inbuffer.find(SEP);
		if (pos == std::string::npos)
		{
			return std::string();
		}

		std::string len_str = inbuffer.substr(0, pos);
		if (len_str.empty())
		{
			return std::string();
		}
		int pack_len = std::stoi(len_str);

		int total = pack_len + len_str.size() + SEP.size() * 2; // 报头+有效载荷+分割符
		if (inbuffer.size() < total)							// 缓冲区里的数据都没有一个完整的报文
		{
			return std::string();
		}

		std::string package = inbuffer.substr(pos + SEP.size(), pack_len);
		inbuffer.erase(0, total); // 去掉一个报文请求，缓冲区不可能每次都只有一个完整请求的报文
		return package;
	}

	// 网络中无法发送结构化的数据！！！
	// 规定协议：报文 = 报头+有效载荷
	//  "有效载荷的长度"\r\n"有效载荷"\r\n
	//  "len"\r\n"_x _op _y"\r\n  -> len: 有效载荷的长度，约定\r\n是分隔符，不参与统计
	class Request
	{
	public:
		Request()
		{
		}

		Request(int n1, int n2, int oper)
			: _n1(n1), _n2(n2), _oper(oper)
		{
		}

		bool Serialize(std::string *out) // 序列化,利用jsoncpp
		{
			// 转成字符串
			Json::Value root;
			root["n1"] = _n1;
			root["n2"] = _n2;
			root["oper"] = _oper;

			Json::FastWriter writer;
			*out = writer.write(root);
			if (out->empty())
				return false;
			return true;
		}

		bool DeSerialize(std::string &in) // 反序列化
		{
			Json::Value root;
			Json::Reader reader;
			bool ret = reader.parse(in, root);
			if (!ret)
				return false;

			_n1 = root["n1"].asUInt();
			_n2 = root["n2"].asUInt();
			_oper = root["oper"].asInt();

			return true;
		}

	public:
		int _n1;	// 数字1
		int _n2;	// 数字2
		char _oper; // 数学运算符号
	};

	class Response
	{
	public:
		Response()
		{
		}
		Response(int result, int code)
			: _result(result), _code(code)
		{
		}

		bool Serialize(std::string *out)
		{
			Json::Value root;
			root["result"] = _result;
			root["code"] = _code;

			Json::FastWriter writer;
			*out = writer.write(root);
			if (out->empty())
				return false;
			return true;
		}

		bool DeSerialize(std::string &in) // 反序列化
		{
			Json::Value root;
			Json::Reader reader;
			bool ret = reader.parse(in, root);
			if (!ret)
				return false;

			_result = root["result"].asInt();
			_code = root["code"].asInt();
			return true;
		}

	public:
		int _result; // 结果
		int _code;	 // 0:success 1: 除0 2: 非法操作 3. 4. 5
	};

	class Factory
	{
	public:
		Factory()
		{
			srand(time(nullptr) ^ getpid());
			opers = "+/*/%^&|";
		}
		std::shared_ptr<Request> BuildRequest()
		{
			int x = rand() % 10 + 1;
			usleep(x * 10);
			int y = rand() % 5; // [01,2,3,4]
			usleep(y * x * 5);
			char oper = opers[rand() % opers.size()];
			std::shared_ptr<Request> req = std::make_shared<Request>(x, y, oper);
			return req;
		}
		std::shared_ptr<Response> BuildResponse()
		{
			return std::make_shared<Response>();
		}
		~Factory()
		{
		}

	private:
		std::string opers;
	};
}
